package com.cmc.cloud.cmclink.doc.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import com.cmc.cloud.cmclink.doc.api.document.emums.SpecialEnum;
import com.cmc.cloud.cmclink.doc.constants.errorconstant.SpecialCargoCntrErrorCodeConstants;
import com.cmc.cloud.cmclink.doc.convert.SpecialCargoCntrConvert;
import com.cmc.cloud.cmclink.doc.entity.CargoCntrTypeRelationDO;
import com.cmc.cloud.cmclink.doc.entity.ContainerMaxPayloadDO;
import com.cmc.cloud.cmclink.doc.entity.SpecialCargoCntrDO;
import com.cmc.cloud.cmclink.doc.entity.SpecialCargoDgDO;
import com.cmc.cloud.cmclink.doc.mapper.CargoCntrTypeRelationMapper;
import com.cmc.cloud.cmclink.doc.mapper.ContainerMaxPayloadMapper;
import com.cmc.cloud.cmclink.doc.mapper.SpecialCargoCntrMapper;
import com.cmc.cloud.cmclink.doc.mapper.SpecialCargoDgMapper;
import com.cmc.cloud.cmclink.doc.service.SpecialCargoCntrService;
import com.cmc.cloud.cmclink.doc.util.sepcial.CommonUtil;
import com.cmc.cloud.cmclink.doc.vo.specialcargocntrvo.SpecialCargoCntrBaseVO;
import com.cmc.cloud.cmclink.doc.vo.specialcargocntrvo.SpecialCargoCntrPageReqVO;
import com.cmc.cloud.cmclink.doc.vo.specialcargocntrvo.SpecialCargoCntrRespVO;
import com.cmes.framework.common.exception.util.ServiceExceptionUtil;
import com.cmes.framework.common.pojo.PageResult;
import com.cmes.framework.mybatis.core.query.LambdaQueryWrapperX;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;


/**
 * 特种货审批的箱型信息 Service 实现类
 *
 * @author 集运管理员
 */
@Service
@Validated
public class SpecialCargoCntrServiceImpl implements SpecialCargoCntrService {

    @Resource
    private SpecialCargoCntrMapper specialCargoCntrMapper;
    @Resource
    private CargoCntrTypeRelationMapper cargoCntrTypeRelationMapper;
    @Resource
    private SpecialCargoDgMapper specialCargoDgMapper;
    @Resource
    private ContainerMaxPayloadMapper containerMaxPayloadMapper;

    @Override
    public Long createSpecialCargoCntr(SpecialCargoCntrBaseVO createReqVO) {
        // 插入
        SpecialCargoCntrDO cntrDO = SpecialCargoCntrConvert.INSTANCE.convert(createReqVO);
        LambdaQueryWrapperX<ContainerMaxPayloadDO> queryWrapperX = new LambdaQueryWrapperX<>();
        queryWrapperX.eqIfPresent(ContainerMaxPayloadDO::getCntrType, cntrDO.getCntrType())
                .eqIfPresent(ContainerMaxPayloadDO::getCntrSize, cntrDO.getCntrSize());
        specialCargoCntrMapper.insert(cntrDO);
        List<Long> dgIds = createReqVO.getDgId();
        if (CollectionUtil.isNotEmpty(dgIds)) {
            //如果这里不为空就说明是要关联的DG，箱型和DG关联中间表维护
            List<CargoCntrTypeRelationDO> newDOList = CollectionUtil.newArrayList();
            for (Long dgId : dgIds) {
                CargoCntrTypeRelationDO cntrDgRelation = new CargoCntrTypeRelationDO();
                cntrDgRelation.setDgId(dgId);
                cntrDgRelation.setApplyId(createReqVO.getApplyId());
                cntrDgRelation.setCntrId(cntrDO.getId());
                cntrDgRelation.setApplyType(SpecialEnum.DG.getValue());
                newDOList.add(cntrDgRelation);
            }
            cargoCntrTypeRelationMapper.insertBatch(newDOList);
        }
        return cntrDO.getId();
    }


    @Override
    public void updateSpecialCargoCntr(SpecialCargoCntrBaseVO updateReqVO) {
        // 校验存在
        validateSpecialCargoCntrExists(updateReqVO.getId());
        // 更新
        SpecialCargoCntrDO updateObj = SpecialCargoCntrConvert.INSTANCE.convert(updateReqVO);
        specialCargoCntrMapper.updateById(updateObj);
        List<Long> dgIdsByClient = updateReqVO.getDgId();
        List<Long> dgIdsByTable = new ArrayList<>();
        List<CargoCntrTypeRelationDO> cntrDgRelations = cargoCntrTypeRelationMapper.selectList(new LambdaQueryWrapperX<CargoCntrTypeRelationDO>().eq(CargoCntrTypeRelationDO::getCntrId, updateReqVO.getId()));
        if (CollectionUtil.isNotEmpty(cntrDgRelations)) {
            dgIdsByTable = cntrDgRelations.stream().map(CargoCntrTypeRelationDO::getDgId).collect(Collectors.toList());
        }
        List<Long>[] symmetricDifference = CommonUtil.getSymmetricDifference(dgIdsByClient, dgIdsByTable);
        List<Long> dgIdsClient = symmetricDifference[0];
        List<Long> dgIdsTable = symmetricDifference[1];
        //客户端传过来的关系表里没有维护的DG新增插入
        if (CollectionUtil.isNotEmpty(dgIdsClient)) {
            List<CargoCntrTypeRelationDO> newDOList = CollectionUtil.newArrayList();
            for (Long dgId : dgIdsClient) {
                CargoCntrTypeRelationDO cntrDgRelation = new CargoCntrTypeRelationDO();
                cntrDgRelation.setDgId(dgId);
                cntrDgRelation.setApplyId(updateReqVO.getApplyId());
                cntrDgRelation.setCntrId(updateReqVO.getId());
                cntrDgRelation.setApplyType(SpecialEnum.DG.getValue());
                newDOList.add(cntrDgRelation);
            }
            cargoCntrTypeRelationMapper.insertBatch(newDOList);
        }
        //客户端没传但是关系表里有的DG删除
        if (CollectionUtil.isNotEmpty(dgIdsTable)) {
            List<Long> deleteIds = cntrDgRelations.stream().filter(relation -> dgIdsTable.contains(relation.getDgId()))
                    .map(CargoCntrTypeRelationDO::getId).collect(Collectors.toList());
            cargoCntrTypeRelationMapper.deleteBatchIds(deleteIds);
        }
    }

    @Override
    public void deleteSpecialCargoCntr(Long id) {
        // 校验存在
        validateSpecialCargoCntrExists(id);
        // 删除
        specialCargoCntrMapper.deleteById(id);
        //也删除中间表的DG关系维护
        List<CargoCntrTypeRelationDO> cntrDgRelations = cargoCntrTypeRelationMapper
                .selectList(new LambdaQueryWrapperX<CargoCntrTypeRelationDO>().eq(CargoCntrTypeRelationDO::getCntrId, id));
        if (CollectionUtil.isNotEmpty(cntrDgRelations)) {
            cargoCntrTypeRelationMapper.delete(new LambdaQueryWrapperX<CargoCntrTypeRelationDO>().inIfPresent(CargoCntrTypeRelationDO::getCntrId, id));
        }
    }

    private void validateSpecialCargoCntrExists(Long id) {
        if (specialCargoCntrMapper.selectById(id) == null) {
            throw ServiceExceptionUtil.exception(SpecialCargoCntrErrorCodeConstants.SPECIAL_CARGO_CNTR_NOT_EXISTS);
        }
    }

    @Override
    public SpecialCargoCntrRespVO getSpecialCargoCntr(Long id) {
        SpecialCargoCntrDO specialCargoCntrDO = specialCargoCntrMapper.selectById(id);
        SpecialCargoCntrRespVO cntrRespVO = SpecialCargoCntrConvert.INSTANCE.convert(specialCargoCntrDO);
        List<CargoCntrTypeRelationDO> cntrDgRelations = cargoCntrTypeRelationMapper.selectList(new LambdaQueryWrapperX<CargoCntrTypeRelationDO>().eq(CargoCntrTypeRelationDO::getCntrId, id));
        if (CollectionUtil.isNotEmpty(cntrDgRelations)) {
            List<Long> dgIds = cntrDgRelations.stream().map(CargoCntrTypeRelationDO::getDgId).collect(Collectors.toList());
            cntrRespVO.setDgId(dgIds);
        }
        return cntrRespVO;
    }

    @Override
    public List<SpecialCargoCntrRespVO> getSpecialCargoCntrList(Long applyId) {
        LambdaQueryWrapperX<SpecialCargoCntrDO> queryWrapperX = new LambdaQueryWrapperX<SpecialCargoCntrDO>()
                .eqIfPresent(SpecialCargoCntrDO::getApplyId, applyId);
        List<SpecialCargoCntrDO> list = specialCargoCntrMapper.selectList(queryWrapperX);
        List<SpecialCargoCntrRespVO> specialCargoCntrRespVos = new ArrayList<>();
        if (CollectionUtil.isEmpty(list)) {
            return specialCargoCntrRespVos;
        }
        specialCargoCntrRespVos = SpecialCargoCntrConvert.INSTANCE.convertList(list);
        specialCargoCntrRespVos = specialCargoCntrRespVos.stream().peek(respVO -> {
            List<CargoCntrTypeRelationDO> cntrDgRelations = cargoCntrTypeRelationMapper
                    .selectList(new LambdaQueryWrapperX<CargoCntrTypeRelationDO>().eq(CargoCntrTypeRelationDO::getCntrId, respVO.getId()));
            if (CollectionUtil.isNotEmpty(cntrDgRelations)) {
                List<Long> dgIds = cntrDgRelations.stream().map(CargoCntrTypeRelationDO::getDgId).collect(Collectors.toList());
                List<SpecialCargoDgDO> originalDgs = specialCargoDgMapper
                        .selectList(new LambdaQueryWrapperX<SpecialCargoDgDO>().inIfPresent(SpecialCargoDgDO::getId, dgIds));
                List<String> unNo = originalDgs.stream().map(SpecialCargoDgDO::getUnNo).collect(Collectors.toList());
                List<String> imoClass = originalDgs.stream().map(SpecialCargoDgDO::getImoClass).collect(Collectors.toList());
                respVO.setDgId(dgIds);
                respVO.setUnNo(unNo);
                respVO.setImoClass(imoClass);
            }
        }).collect(Collectors.toList());
        return specialCargoCntrRespVos;
    }

    @Override
    public PageResult<SpecialCargoCntrRespVO> getSpecialCargoCntrPage(SpecialCargoCntrPageReqVO reqVO) {

        LambdaQueryWrapperX<SpecialCargoCntrDO> queryWrapperX = new LambdaQueryWrapperX<SpecialCargoCntrDO>()
                .eqIfPresent(SpecialCargoCntrDO::getApplyId, reqVO.getApplyId());
        PageResult<SpecialCargoCntrDO> specialCargoCntrs = specialCargoCntrMapper.selectPage(reqVO, queryWrapperX);
        List<SpecialCargoCntrRespVO> results = SpecialCargoCntrConvert.INSTANCE.convertList(specialCargoCntrs.getList());
        if (CollectionUtil.isNotEmpty(results)) {
            results = results.stream().peek(respVO -> {
                        List<CargoCntrTypeRelationDO> cntrDgRelations = cargoCntrTypeRelationMapper
                                .selectList(new LambdaQueryWrapperX<CargoCntrTypeRelationDO>().eq(CargoCntrTypeRelationDO::getCntrId, respVO.getId()));
                        if (CollectionUtil.isNotEmpty(cntrDgRelations)) {
                            List<Long> dgIds = cntrDgRelations.stream().map(CargoCntrTypeRelationDO::getDgId).collect(Collectors.toList());
                            respVO.setDgId(dgIds);
                        }
                    })
                    .collect(Collectors.toList());
        }
        return new PageResult<>(results, specialCargoCntrs.getTotal());
    }
}
